/*
 *    Copyright (c) 2018-2025, nart All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: nart
 */
package com.nai365.nart.operation.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nai365.nart.common.core.constant.SecurityConstants;
import com.nai365.nart.common.core.util.R;
import com.nai365.nart.common.security.util.SecurityUtils;
import com.nai365.nart.member.dto.SimpleMemberDto;
import com.nai365.nart.member.entity.Member;
import com.nai365.nart.member.feign.RemoteMemberService;
import com.nai365.nart.operation.dto.BuySpuDto;
import com.nai365.nart.operation.dto.BuySpuNotifyDto;
import com.nai365.nart.operation.entity.Preemption;
import com.nai365.nart.operation.entity.PreemptionUse;
import com.nai365.nart.operation.exception.PreemptionException;
import com.nai365.nart.operation.mapper.PreemptionMapper;
import com.nai365.nart.operation.mapper.PreemptionUseMapper;
import com.nai365.nart.operation.service.PreemptionService;
import com.nai365.nart.operation.dto.PreemptionDto;
import com.nai365.nart.operation.service.ProductService;
import com.nai365.nart.product.api.feign.RemoteCategoryService;
import com.nai365.nart.product.api.feign.RemoteSpuService;
import com.nai365.nart.product.entity.Category;
import com.nai365.nart.product.entity.SpuInfo;
import com.nai365.nart.seckill.api.feign.SeckillFeignService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.klock.annotation.Klock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 优先购
 *
 * @author baogs
 * @date 2022-07-01 11:13:17
 */
@Service
@AllArgsConstructor
@Slf4j
public class PreemptionServiceImpl extends ServiceImpl<PreemptionMapper, Preemption> implements PreemptionService {


	private final PreemptionMapper preemptionMapper;

	private final ProductService productService;

	private final RemoteSpuService remoteSpuService;

	private final RemoteMemberService remoteMemberService;

	private final SeckillFeignService seckillFeignService;

	private final PreemptionUseMapper preemptionUseMapper;

	private static final Map<Integer, String> TYPE_MAP = new HashMap<>();

	static {
		TYPE_MAP.put(1, "不限制");
		TYPE_MAP.put(2, "限制藏品类别");
		TYPE_MAP.put(3, "限制藏品");
	}

	@Override
	public Page<PreemptionDto> page(Page<Preemption> page, Wrapper<Preemption> preemption) {
		List<PreemptionDto> result = new ArrayList<>();
		//查询分页数据
		page = preemptionMapper.selectPage(page, preemption);
		Page<PreemptionDto> resultPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
		//组装使用到的会员ID列表，SPU ID列表

		List<Long> spuIdList = new ArrayList<>();
		Set<Long> memberIdSet = new HashSet<>();
		for (Preemption p : page.getRecords()) {
			if (p.getArtifactId() != null) {
				spuIdList.add(p.getArtifactId());
			}
			if (p.getUserId() != null) {
				memberIdSet.add(p.getUserId());
			}
		}
		//远程查询类别、SPU、会员数据
		Map<Long, Category> categoryMap = this.productService.getAllCategoryMap();
		Map<Long, SpuInfo> spuMap = this.getSpuInfoMapByIds(spuIdList);
		Map<Long, SimpleMemberDto> memberMap = this.getMemberMapByIds(memberIdSet);
		//组装结果数据
		for (Preemption p : page.getRecords()) {
			PreemptionDto vo = preemption2PreemptionVO(p, categoryMap, spuMap, memberMap);
			result.add(vo);
		}
		resultPage.setRecords(result);
		return resultPage;
	}

	private PreemptionDto preemption2PreemptionVO(
			Preemption preemption, Map<Long, Category> categoryMap, Map<Long, SpuInfo> spuMap,
			Map<Long, SimpleMemberDto> memberMap) {
		PreemptionDto vo = new PreemptionDto();
		BeanUtils.copyProperties(preemption, vo);
		vo.setTypeName(TYPE_MAP.get(vo.getType()));
		vo.setEffectName(vo.getEffect() == 1 ? "有效" : "无效");
		Category category = categoryMap.get(preemption.getCategoryId());
		if (category != null) {
			vo.setCategoryName(category.getName());
		}
		SpuInfo spu = spuMap.get(preemption.getArtifactId());
		if (spu != null) {
			vo.setArtifactName(spu.getSpuName());
		}
		SimpleMemberDto member = memberMap.get(preemption.getUserId());
		if (member != null) {
			vo.setMember(member);
		}
		return vo;
	}


	@Override
	public List<PreemptionDto> findBySpu(Long spuId) throws PreemptionException {
		SpuInfo spu = this.getSpuInfoById(spuId);
		if (spu == null) {
			throw new PreemptionException("藏品不存在!");
		}
		LocalDateTime now = LocalDateTime.now();
		if (now.isAfter(spu.getPrioritySellBeginTime()) && now.isBefore(spu.getPrioritySellEndTime())) {
			List<PreemptionDto> result = new ArrayList<>();
			List<Preemption> list = this.findBest(spu);
			//组装使用到的会员ID列表，SPU ID列表
			List<Long> spuIdList = new ArrayList<>();
			List<Long> memberIdList = new ArrayList<>();
			for (Preemption p : list) {
				if (p.getArtifactId() != null) {
					spuIdList.add(p.getArtifactId());
				}
				if (p.getUserId() != null) {
					memberIdList.add(p.getUserId());
				}
			}
			//远程查询类别、SPU、会员数据
			Map<Long, Category> categoryMap = this.productService.getAllCategoryMap();
			Map<Long, SpuInfo> spuMap = this.getSpuInfoMapByIds(spuIdList);
			Map<Long, SimpleMemberDto> memberMap = this.getMemberMapByIds(memberIdList);
			//组装结果数据
			for (Preemption p : list) {
				PreemptionDto vo = preemption2PreemptionVO(p, categoryMap, spuMap, memberMap);
				result.add(vo);
			}
			return result;
		} else {
			throw new PreemptionException("该藏品优先购已结束!");
		}
	}

	private List<Preemption> findBest(SpuInfo spu) {
		List<Preemption> result = new ArrayList<>();
		QueryWrapper<Preemption> wrapper = new QueryWrapper<>();
		wrapper.eq("user_id", SecurityUtils.getUser().getId());
		wrapper.eq("effect", 1);
		wrapper.eq("del_flag", "0");
		wrapper.orderByDesc("effect_end_time");
		List<Preemption> preemptionList = preemptionMapper.selectList(wrapper);
		if (preemptionList != null && !preemptionList.isEmpty()) {
			//限制藏品的优先购
			Stream<Preemption> type3 = preemptionList.stream().filter(
					u -> u.getType() == 3 && Objects.equals(u.getArtifactId(), spu.getId())
			).filter(
					u -> u.getEffectEndTime() == null || u.getEffectEndTime().isAfter(LocalDateTime.now())
			).filter(u -> u.getQuantity() - u.getUseCount() > 0);
			result.addAll(type3.collect(Collectors.toList()));
			//限制藏品类别的优先购
			Stream<Preemption> type2 = preemptionList.stream().filter(
					u -> u.getType() == 2 && Objects.equals(u.getCategoryId(), spu.getCatalogId())
			).filter(
					u -> u.getEffectEndTime() == null || u.getEffectEndTime().isAfter(LocalDateTime.now())
			).filter(u -> u.getQuantity() - u.getUseCount() > 0);
			;
			result.addAll(type2.collect(Collectors.toList()));
			//不限制的优先购
			Stream<Preemption> type1 = preemptionList.stream().filter(u -> u.getType() == 1)
					.filter(u -> u.getEffectEndTime() == null || u.getEffectEndTime().isAfter(LocalDateTime.now()))
					.filter(u -> u.getQuantity() - u.getUseCount() > 0);
			result.addAll(type1.collect(Collectors.toList()));
		}
		return result;
	}


	private Map<Long, SpuInfo> getSpuInfoMapByIds(List<Long> ids) {
		Map<Long, SpuInfo> result = new HashMap<>();
		if (!ids.isEmpty()) {
			R<List<SpuInfo>> remoteResult = this.remoteSpuService.listByIds(ids, SecurityConstants.FROM_IN);
			if (remoteResult.getCode() == 0 && remoteResult.getData() != null && !remoteResult.getData().isEmpty()) {
				for (SpuInfo spu : remoteResult.getData()) {
					result.put(spu.getId(), spu);
				}
			}
		}
		return result;
	}

	private Map<Long, SimpleMemberDto> getMemberMapByIds(Collection<Long> ids) {
		Map<Long, SimpleMemberDto> result = new HashMap<>();
		R<List<SimpleMemberDto>> remoteResult = this.remoteMemberService.listByIds(ids);
		if (remoteResult.getCode() == 0 && remoteResult.getData() != null && !remoteResult.getData().isEmpty()) {
			for (SimpleMemberDto member : remoteResult.getData()) {
				result.put(member.getId(), member);
			}
		}
		return result;
	}

	private SpuInfo getSpuInfoById(Long id) {
		R<SpuInfo> remoteResult = remoteSpuService.getById(id, SecurityConstants.FROM_IN);
		if (remoteResult.getCode() == 0) {
			return remoteResult.getData();
		}
		return null;
	}

	@Override
	@Klock(keys = {"#buySpuDto.preemptionId"})
	@Transactional
	public String buySpu(BuySpuDto buySpuDto) throws Exception {
		LocalDateTime now = LocalDateTime.now();
		Preemption preemption = this.getById(buySpuDto.getPreemptionId());
		R<SpuInfo> remoteResult = remoteSpuService.getById(buySpuDto.getSpuId(), SecurityConstants.FROM_IN);
		SpuInfo spuInfo = null;
		Long userId = SecurityUtils.getUser().getId();
		if (remoteResult.getCode() == 0) {
			spuInfo = remoteResult.getData();
		} else {
			throw new Exception("不能获取藏品信息!");
		}
		if (!Objects.equals(preemption.getUserId(), userId)) {
			throw new Exception("你选择的优先购不是你的优先购!");
		}
		if (preemption.getEffect() == 0) {
			throw new Exception("你选择的优先购无效!");
		}
		if (preemption.getEffectEndTime() != null) {
			if (now.isAfter(preemption.getEffectEndTime())) {
				throw new Exception("你选择的优先购已经过期!");
			}
		}
		if (preemption.getType() == 3) {
			if (!Objects.equals(preemption.getArtifactId(), buySpuDto.getSpuId())) {
				throw new Exception("你选择的优先购不使用该藏品!");
			}
		}
		if (preemption.getType() == 2) {
			if (!Objects.equals(preemption.getCategoryId(), spuInfo.getCatalogId())) {
				throw new Exception("你选择的优先购不使用该藏品!");
			}
		}
		if (preemption.getUseCount() >= preemption.getQuantity()) {
			throw new Exception("你选择的优先购次数已用完!");
		}
		if (spuInfo.getPublishStatus() != 1) {
			throw new Exception("该藏品未上架或已下架!");
		}
		if (now.isBefore(spuInfo.getPrioritySellBeginTime())) {
			throw new Exception("优先购还未开始!");
		}
		if (now.isAfter(spuInfo.getPrioritySellEndTime())) {
			throw new Exception("优先购已结束!");
		}
		R<String> remoteOrder = seckillFeignService.seckill(
				buySpuDto.getSpuId() + "",
				1, buySpuDto.getPreemptionId(), userId,
				SecurityConstants.FROM_IN
		);
		if (remoteOrder.getCode() == 0) {
			String orderNo = remoteOrder.getData();
			if (StringUtils.isEmpty(orderNo)) {
				throw new Exception("优先购抢购失败!");
			}
			preemption.setUseCount(preemption.getUseCount() + 1);
			this.updateById(preemption);
			PreemptionUse preemptionUse = PreemptionUse.builder()
					.preemptionId(buySpuDto.getPreemptionId())
					.userId(userId)
					.orderNo(orderNo)
					.quantity(1)
					.build();
			preemptionUseMapper.insert(preemptionUse);
			return orderNo;
		} else {
			throw new Exception(remoteOrder.getMsg());
		}
	}

	@Override
	@Klock(keys = {"#buySpuNotifyDto.orderNo"})
	@Transactional
	public Boolean buySpuNotify(BuySpuNotifyDto buySpuNotifyDto) throws Exception {
		if (buySpuNotifyDto.getIsSuccess()) {
			log.info("支付成功，不需要处理！");
		} else {
			LambdaQueryWrapper<PreemptionUse> queryWrapper = Wrappers.lambdaQuery();
			queryWrapper.eq(PreemptionUse::getOrderNo, buySpuNotifyDto.getOrderNo());
			Preemption preemption = this.getById(Long.valueOf(buySpuNotifyDto.getDataId()));
			if (preemption != null) {
				preemption.setUseCount(preemption.getUseCount() + 1);
				this.updateById(preemption);
				List<PreemptionUse> preemptionUseList = preemptionUseMapper.selectList(queryWrapper);
				if (preemptionUseList != null && !preemptionUseList.isEmpty()) {
					PreemptionUse preemptionUse = preemptionUseList.get(0);
					this.removeById(preemptionUse.getId());
				}
			} else {
				throw new Exception("找不到优先购！");
			}
		}
		return true;
	}

	@Override
	public PreemptionDto getPreemptionDtoBy(Long id) {
		Preemption preemption = this.getById(id);
		Map<Long, Category> categoryMap = this.productService.getAllCategoryMap();
		Map<Long, SpuInfo> spuMap = new HashMap<>();
		if (preemption.getArtifactId() != null) {
			List<Long> spuIdList = new ArrayList<>();
			spuIdList.add(preemption.getArtifactId());
			this.getSpuInfoMapByIds(spuIdList);
		}
		Set<Long> memberIdSet = new HashSet<>();
		memberIdSet.add(preemption.getUserId());
		Map<Long, SimpleMemberDto> memberMap = this.getMemberMapByIds(memberIdSet);
		return preemption2PreemptionVO(preemption, categoryMap, spuMap, memberMap);
	}
}
